package com.tools.starter.swagger.aop;

import com.alibaba.fastjson.JSON;
import com.tools.starter.swagger.annotation.Mock;
import com.tools.starter.swagger.exception.NeedMockException;
import com.tools.starter.swagger.sqlite.MockEntity;
import com.tools.starter.swagger.sqlite.SQLiteManager;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.util.Objects;

@Slf4j
@Aspect
public class MockAop {

    @Around(value = "@annotation(com.tools.starter.swagger.annotation.Mock)")
    public Object processJoint(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            return joinPoint.proceed();
        } catch (NeedMockException e) {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Mock mock = signature.getMethod().getAnnotation(Mock.class);
            String path = mock.path();

            //fixme 如果存在默认的文件 则优先读取文件
            if (StringUtils.hasLength(path)) {
                try (InputStream in = MockAop.class.getClassLoader().getResourceAsStream(path)) {
                    byte[] data = new byte[in.available()];
                    in.read(data);
                    String str = new String(data);
                    if (!StringUtils.hasLength(str)) {
                        return null;
                    } else {
                        return JSON.parseObject(str, signature.getMethod().getGenericReturnType());
                    }
                } catch (Exception exception) {
                    log.error("local path:{} not exist", path);
                }
            }
            //fixme 读取sqlite数据库设置数据
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            path = request.getRequestURI();

            String[] bath = getPath(signature, request);
            if (Objects.nonNull(bath) && bath.length > 0) {
                RequestMapping requestMapping = joinPoint.getTarget().getClass().getAnnotation(RequestMapping.class);
                if (Objects.nonNull(requestMapping)) {
                    String[] base = requestMapping.path().length> 0 ? requestMapping.path() : requestMapping.value();
                    path = (Objects.nonNull(base) && base.length > 0 ? base[0] : "")+ bath[0];
                }
            }

            MockEntity entity = SQLiteManager.selectByPathUrl(path);
            return JSON.parseObject(entity.getMockData(), signature.getMethod().getGenericReturnType());
        } catch (Exception e) {
            throw e;
        }
    }

    private String[] getPath(MethodSignature signature, HttpServletRequest request) {
        String methodType = request.getMethod();
        String[] bath = null;
        RequestMapping req= signature.getMethod().getAnnotation(RequestMapping.class);
        if (Objects.isNull(req)) {
            if ("POST".equalsIgnoreCase(methodType)) {
                PostMapping post = signature.getMethod().getAnnotation(PostMapping.class);
                bath = post.path().length > 0 ? post.path() : post.value();
            }
            if ("GET".equalsIgnoreCase(methodType)) {
                GetMapping get = signature.getMethod().getAnnotation(GetMapping.class);
                bath = get.path().length > 0 ? get.path() : get.value();
            }
            if ("DELETE".equalsIgnoreCase(methodType)) {
                DeleteMapping get = signature.getMethod().getAnnotation(DeleteMapping.class);
                bath = get.path().length > 0 ? get.path() : get.value();
            }
            if ("PATCH".equalsIgnoreCase(methodType)) {
                PatchMapping get = signature.getMethod().getAnnotation(PatchMapping.class);
                bath = get.path().length > 0 ? get.path() : get.value();
            }
            if ("PUT".equalsIgnoreCase(methodType)) {
                PutMapping get = signature.getMethod().getAnnotation(PutMapping.class);
                bath = get.path().length > 0 ? get.path() : get.value();
            }
        } else {
            bath = req.path().length >0 ? req.path() : req.value();
        }
        return bath;
    }
}
